﻿/*------------------------------------------------------------------------

LIGHTSOURCERD.HPP v1.0.1

Copyright 楊志賢 CxxlMan, 2014
All Rights Reserved

------------------------------------------------------------------------*/

#if !defined(__LIGHTSOURCERD_HPP_Cxxl3D)
#define __LIGHTSOURCERD_HPP_Cxxl3D

//#include <CENTRALIZEDMGR.HPP>
#include <Sys\C3DNODE.HPP>
#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
#include <Sys\RENDERUNIT.HPP>
#include <Sys\VECTOR.HPP>


namespace Cxxl3D
{

// Render 須實作
class ILightSourceVisitor;

// Render 單元要叫用 ILightSourceMgrRD 提供給其叫用的功能，須繼承此介面
class ILightSourceMgrBridge;

class ILightAmbient:virtual public CxxlMan::cxxlPreserve2
{
  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Ambient) = 0;

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  ILightAmbient()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ILightAmbient_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  virtual ~ILightAmbient(){}


public:

  // 取得以下資料
  // Ambient = 附增環境顏色值 rgba
  virtual void cxxlFASTCALL GetData(C3DVector4 &Ambient) = 0;


  // 建立 ILightDirectional 物件，失敗傳回 NULL
  // Ambient = 附增環境顏色值 rgba
  static CxxlMan::Smart_Ptr<ILightAmbient> cxxlFASTCALL Create(const C3DVector4 &Ambient)
  {
    CxxlMan::Smart_Ptr<ILightAmbient> r = CxxlMan::Preserve2_Cast<ILightAmbient>( CxxlMan::cxxlCM_GetElement(ILightAmbient_ClassID, IRenderDatagram_Group) );
    if(r.isNULL() == false)
      r->SysInit(Ambient);
    return r;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightAmbient>;  // Preserve2 元件須加上這個
};

class ILightSource:public IC3D_NodeHost
{

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IC3D_NodeHost::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  ILightSource()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID
  {
  }

  // Destructor
  virtual ~ILightSource(){}


public:

  virtual void cxxlFASTCALL Accept(ILightSourceVisitor &visitor) = 0;

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightSource>;  // Preserve2 元件須加上這個

};


class ILightDirectional:public ILightSource
{
  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional) = 0;

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightSource::Ref(F))
      return true;
    else
      return false;
  }


  // Constructor
  ILightDirectional()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ILightDirectional_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~ILightDirectional(){}
public:

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Directional = 射出方向
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Directional) = 0;


  // 建立 ILightDirectional 物件，失敗傳回 NULL
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 指定光線顏色值 rgba
  // Directional = 射出方向
  static CxxlMan::Smart_Ptr<ILightDirectional> cxxlFASTCALL Create(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional)
  {
    CxxlMan::Smart_Ptr<ILightDirectional> r = CxxlMan::Preserve2_Cast<ILightDirectional>( CxxlMan::cxxlCM_GetElement(ILightDirectional_ClassID, IRenderDatagram_Group) );
    if(r.isNULL() == false)
      r->SysInit(Specular,Ambient,Color,Directional);
    return r;
  }

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightDirectional>;  // Preserve2 元件須加上這個
};


class ILightPoint:public ILightSource
{
  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Position, const C3DVector4 &Attenuation) = 0;
protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightSource::Ref(F))
      return true;
    else
      return false;
  }


  // Constructor
  ILightPoint()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ILightPoint_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~ILightPoint(){}
public:

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Position = 點光源的位置
  // Attenuation = 隨距離的衰減值，公式 1/(CONSTANT + LINEAR*d + QUADRATIC*d^2) 其中 d 為距離
  //               Attenuation 的前 3 個欄位值為公式中的 CONSTANT、LINEAR、QUADRATIC 值
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Position, C3DVector4 &Attenuation) = 0;


  // 建立 ILightDirectional 物件，失敗傳回 NULL
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 指定光線顏色值 rgba
  // Position = 點光源的位置
  // Attenuation = 隨距離的衰減值，公式 1/(CONSTANT + LINEAR*d + QUADRATIC*d^2) 其中 d 為距離
  //               Attenuation 的前 3 個欄位值為公式中的 CONSTANT、LINEAR、QUADRATIC 值
  static CxxlMan::Smart_Ptr<ILightPoint> cxxlFASTCALL Create(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Position, const C3DVector4 &Attenuation)
  {
    CxxlMan::Smart_Ptr<ILightPoint> r = CxxlMan::Preserve2_Cast<ILightPoint>( CxxlMan::cxxlCM_GetElement(ILightPoint_ClassID, IRenderDatagram_Group) );
    if(r.isNULL() == false)
      r->SysInit(Specular,Ambient,Color,Position,Attenuation);
    return r;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightPoint>;  // Preserve2 元件須加上這個
};


class ILightSpot:public ILightSource
{
  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional, const C3DVector4 &Position, const C3DVector4 &Attenuation,
    C3D_FLOAT SpotlightCutoff, C3D_FLOAT SpotlightExponent) = 0;


protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightSource::Ref(F))
      return true;
    else
      return false;
  }


  // Constructor
  ILightSpot()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ILightSpot_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~ILightSpot(){}
public:

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Directional = 射出方向
  // Position = 點光源的位置
  // Attenuation = 隨距離的衰減值，公式 1/(CONSTANT + LINEAR*d + QUADRATIC*d^2) 其中 d 為距離
  //               Attenuation 的前 3 個欄位值為公式中的 CONSTANT、LINEAR、QUADRATIC 值
  // SpotlightCutoff = 光柱圓錐一半的角度
  // SpotlightExponent = 光柱圓錐的角度衰減
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Directional, C3DVector4 &Position, C3DVector4 &Attenuation, 
    C3D_FLOAT &SpotlightCutoff, C3D_FLOAT &SpotlightExponent) = 0;

  // 建立 ILightSpot 物件，失敗傳回 NULL
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 指定光線顏色值 rgba
  // Directional = 射出方向
  // Position = 點光源的位置
  // Attenuation = 隨距離的衰減值，公式 1/(CONSTANT + LINEAR*d + QUADRATIC*d^2) 其中 d 為距離
  //               Attenuation 的前 3 個欄位值為公式中的 CONSTANT、LINEAR、QUADRATIC 值
  // SpotlightCutoff = 光柱圓錐一半的角度
  // SpotlightExponent = 光柱圓錐的角度衰減
  static CxxlMan::Smart_Ptr<ILightSpot> cxxlFASTCALL Create(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional, const C3DVector4 &Position, const C3DVector4 &Attenuation, 
    C3D_FLOAT SpotlightCutoff, C3D_FLOAT SpotlightExponent)
  {
    CxxlMan::Smart_Ptr<ILightSpot> r = CxxlMan::Preserve2_Cast<ILightSpot>( CxxlMan::cxxlCM_GetElement(ILightSpot_ClassID, IRenderDatagram_Group) );
    if(r.isNULL() == false)
      r->SysInit(Specular,Ambient,Color,Directional,Position,Attenuation,SpotlightCutoff,SpotlightExponent);
    return r;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightSpot>;  // Preserve2 元件須加上這個
};

class ILightSourceMgrRD:public IRenderDatagram
{

  // 由 Render 單元叫用，並恢復設定為 false
  virtual bool cxxlFASTCALL isModified() = 0;


  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return ILightSourceMgr_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IRenderDatagram::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  ILightSourceMgrRD()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(ILightSourceMgr_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  virtual ~ILightSourceMgrRD()
  {}

public:

  // 設定環境光
  virtual void cxxlFASTCALL SetAmbient(const CxxlMan::Smart_Ptr<ILightAmbient> &Ambient) = 0;

  // 取得環境光
  virtual void cxxlFASTCALL GetAmbient(CxxlMan::Smart_Ptr<ILightAmbient> &Ambient) = 0;


  // 最多只能放進 8 個，若滿了回覆 false
  virtual bool cxxlFASTCALL Bind(const CxxlMan::Smart_Ptr<ILightSource> &ILightSource_Arg) = 0;

  // 剔除指定的光源
  virtual void cxxlFASTCALL UnBind(const CxxlMan::Smart_Ptr<ILightSource> &ILightSource_Arg) = 0;

  // 取得所有光源
  virtual CxxlMan::Smart_Ptr<CxxlMan::cxxlList<ILightSource> > GetILightSources() = 0;

  // 從永存資料產生 ILightSourceMgrRD 物件
  // 失敗傳回 NULL
  static CxxlMan::Smart_Ptr<ILightSourceMgrRD> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &BackupName, const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg)
  {
    CxxlMan::Smart_Ptr<cxxlPreserve2> cxxlPreserve2_Ptr(NULL);
    CxxlMan::REGENERARETURN_TYPE rt = cxxlCM_Regenera(cxxlPreserve2_Ptr, BackupName, IcxxlStorage_Arg, true);

    if(rt == CxxlMan::Regenera_Success)
      return CxxlMan::Smart_Cast<ILightSourceMgrRD>(cxxlPreserve2_Ptr);
    else
      return NULL;
  }


  // 建立 ILightSourceMgrRD 物件，失敗傳回 NULL
  static CxxlMan::Smart_Ptr<ILightSourceMgrRD> cxxlFASTCALL Create()
  {
    return CxxlMan::Preserve2_Cast<ILightSourceMgrRD>( CxxlMan::cxxlCM_GetElement(ILightSourceMgr_ClassID, IRenderDatagram_Group) );
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<ILightSourceMgrRD>;  // Preserve2 元件須加上這個
  friend class ILightSourceMgrBridge;
};


// Render 單元要叫用 ILightSourceMgrRD 提供給其叫用的功能，須繼承此介面
class ILightSourceMgrBridge
{

protected:

  // 由 Render 單元叫用，並恢復設定為 false
  bool cxxlFASTCALL isModified(const CxxlMan::Smart_Ptr<ILightSourceMgrRD> &ILightSourceMgrRD_Arg)
  {
    return ILightSourceMgrRD_Arg->isModified();
  }


public:
  ILightSourceMgrBridge(){}
  ~ILightSourceMgrBridge(){}

};

// Render 單元須實作
class ILightSourceVisitor
{
public:
  // Constructor
  ILightSourceVisitor(){}
  // Destructor
  virtual ~ILightSourceVisitor(){}

  
  virtual void cxxlFASTCALL VisitLightDirectional(const CxxlMan::Smart_Ptr<ILightDirectional> &ILightDirectional_Arg) = 0;
  virtual void cxxlFASTCALL VisitLightPoint(const CxxlMan::Smart_Ptr<ILightPoint> &ILightPoint_Arg) = 0;  
  virtual void cxxlFASTCALL VisitLightSpot(const CxxlMan::Smart_Ptr<ILightSpot> &ILightSpot_Arg) = 0;
};


}   /* namespace Cxxl3D */
#endif

